package com.itjin.service.impl;

import com.aliyun.oss.OSS;
import com.aliyun.oss.model.PutObjectRequest;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itjin.mapper.LearningMaterialMapper;
import com.itjin.model.domain.dto.LearningMaterialUploadDTO;
import com.itjin.model.domain.dto.MaterialAuditDTO;
import com.itjin.model.domain.dto.MaterialBatchAuditDTO;
import com.itjin.model.domain.dto.StatDTO;
import com.itjin.model.domain.entity.LearningMaterial;
import com.itjin.model.domain.entity.User;
import com.itjin.model.domain.vo.LearningMaterialVO;
import com.itjin.model.result.Result;
import com.itjin.service.FileService;
import com.itjin.utils.UserHolder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * 文件服务实现类
 */
@Service
@Slf4j
public class FileServiceImpl implements FileService {

    @Resource
    private OSS ossClient;

    @Resource
    private LearningMaterialMapper learningMaterialMapper;

    @Resource
    private HttpServletRequest request;

    @Value("${alibaba.cloud.oss.bucket-name}")
    private String bucketName;

    @Value("${alibaba.cloud.oss.endpoint}")
    private String endpoint;

    // 允许上传的文件类型
    private static final List<String> ALLOWED_FILE_TYPES = Arrays.asList(
            "pdf", "doc", "docx", "ppt", "pptx", "xls", "xlsx", "txt", "zip", "rar"
    );

    // 文件大小限制 (50MB)
    private static final long MAX_FILE_SIZE = 50 * 1024 * 1024;

    // ==================== 用户端方法实现 ====================

    @Override
    @Transactional
    public Result<LearningMaterialVO> uploadLearningMaterial(LearningMaterialUploadDTO uploadDTO) {
        try {
            // 验证用户ID
            if (uploadDTO.getUserId() == null) {
                return Result.failure(400, "用户ID不能为空");
            }

            // 验证文件URL是否有效
            if (uploadDTO.getFileUrl() == null || uploadDTO.getFileUrl().trim().isEmpty()) {
                return Result.failure(400, "文件URL不能为空");
            }

            // 验证文件大小
            if (uploadDTO.getFileSize() > MAX_FILE_SIZE) {
                return Result.failure(400, "文件大小不能超过50MB");
            }

            // 验证文件类型
            String fileExtension = uploadDTO.getFileType().toLowerCase();
            if (!ALLOWED_FILE_TYPES.contains(fileExtension)) {
                return Result.failure(400, "不支持的文件类型，支持的类型: " + String.join(", ", ALLOWED_FILE_TYPES));
            }

            // 创建学习资料记录
            LearningMaterial material = new LearningMaterial();
            BeanUtils.copyProperties(uploadDTO, material);
            
            // 设置文件相关信息
            material.setFilePath(uploadDTO.getFileUrl());
            material.setUploaderId(uploadDTO.getUserId());
            material.setViewCount(0);
            material.setDownloadCount(0);
            material.setAuditStatus(0); // 待审核状态

            // 保存到数据库
            learningMaterialMapper.insert(material);

            // 构建返回VO（这里不需要用户名，因为没有当前用户上下文）
            LearningMaterialVO materialVO = buildMaterialVO(material, null);

            log.info("用户{}创建学习资料成功: {}", uploadDTO.getUserId(), material.getTitle());
            return Result.success(materialVO);

        } catch (Exception e) {
            log.error("创建学习资料失败", e);
            return Result.failure(500, "创建失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional
    public Result<Void> updateLearningMaterial(Integer id, LearningMaterialUploadDTO updateDTO) {
        try {
            User currentUser = getCurrentUser();
            if (currentUser == null) {
                return Result.failure(401, "用户未登录");
            }

            // 检查是否可以修改
            int canModify = learningMaterialMapper.canModifyMaterial(id, currentUser.getId());
            if (canModify == 0) {
                return Result.failure(403, "只能修改待审核状态的资料");
            }

            // 获取原资料信息
            LearningMaterial material = learningMaterialMapper.getMaterialById(id);
            if (material == null) {
                return Result.failure(404, "资料不存在");
            }

            // 更新资料信息
            BeanUtils.copyProperties(updateDTO, material);
            learningMaterialMapper.updateById(material);

            log.info("用户{}修改学习资料成功: {}", currentUser.getId(), material.getTitle());
            return Result.success();

        } catch (Exception e) {
            log.error("修改学习资料失败", e);
            return Result.failure(500, "修改失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional
    public Result<Void> deleteLearningMaterial(Integer id) {
        try {
            User currentUser = getCurrentUser();
            if (currentUser == null) {
                return Result.failure(401, "用户未登录");
            }

            // 检查是否可以删除
            int canModify = learningMaterialMapper.canModifyMaterial(id, currentUser.getId());
            if (canModify == 0) {
                return Result.failure(403, "只能删除待审核状态的资料");
            }

            // 软删除
            LearningMaterial material = new LearningMaterial();
            material.setId(id);
            material.setIsDelete(1);
            learningMaterialMapper.updateById(material);

            log.info("用户{}删除学习资料成功: {}", currentUser.getId(), id);
            return Result.success();

        } catch (Exception e) {
            log.error("删除学习资料失败", e);
            return Result.failure(500, "删除失败: " + e.getMessage());
        }
    }

    @Override
    public Result<Page<LearningMaterialVO>> getPublicMaterials(Integer current, Integer size,
                                                               String collegeName, String subjectType,
                                                               String academicYear, Integer semester,
                                                               String fileType, String keyword,
                                                               String orderBy) {
        try {
            Page<LearningMaterialVO> page = new Page<>(current, size);
            Page<LearningMaterialVO> result = learningMaterialMapper.getPublicMaterials(
                    page, collegeName, subjectType, academicYear, semester, fileType, keyword, orderBy);

            // 设置审核状态文本
            result.getRecords().forEach(this::setAuditStatusText);

            return Result.success(result);

        } catch (Exception e) {
            log.error("查询公开资料列表失败", e);
            return Result.failure(500, "查询失败: " + e.getMessage());
        }
    }

    @Override
    public Result<Page<LearningMaterial>> getUserMaterials(Integer current, Integer size) {
        try {
            User currentUser = getCurrentUser();
            if (currentUser == null) {
                return Result.failure(401, "用户未登录");
            }

            Page<LearningMaterial> page = new Page<>(current, size);
            Page<LearningMaterial> result = learningMaterialMapper.getUserMaterials(page, currentUser.getId());

            return Result.success(result);

        } catch (Exception e) {
            log.error("查询用户资料列表失败", e);
            return Result.failure(500, "查询失败: " + e.getMessage());
        }
    }

    @Override
    public Result<Page<LearningMaterial>> getUserPendingMaterials(Integer current, Integer size) {
        try {
            User currentUser = getCurrentUser();
            if (currentUser == null) {
                return Result.failure(401, "用户未登录");
            }

            Page<LearningMaterial> page = new Page<>(current, size);
            Page<LearningMaterial> result = learningMaterialMapper.getUserPendingMaterials(page, currentUser.getId());

            return Result.success(result);

        } catch (Exception e) {
            log.error("查询用户待审核资料列表失败", e);
            return Result.failure(500, "查询失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional
    public Result<LearningMaterialVO> getMaterialDetail(Integer id) {
        try {
            LearningMaterial material = learningMaterialMapper.getMaterialById(id);
            if (material == null) {
                return Result.failure(404, "资料不存在");
            }

            // 如果是已审核通过的资料，增加浏览次数
            if (material.getAuditStatus() == 1) {
                learningMaterialMapper.incrementViewCount(id);
                material.setViewCount(material.getViewCount() + 1);
            }

            // 构建VO
            LearningMaterialVO materialVO = buildMaterialVO(material, null);

            return Result.success(materialVO);

        } catch (Exception e) {
            log.error("获取资料详情失败", e);
            return Result.failure(500, "获取详情失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional
    public Result<String> downloadMaterial(Integer id) {
        try {
            LearningMaterial material = learningMaterialMapper.getMaterialById(id);
            if (material == null) {
                return Result.failure(404, "资料不存在");
            }

            // 只有审核通过的资料才能下载
            if (material.getAuditStatus() != 1) {
                return Result.failure(403, "资料未通过审核，无法下载");
            }

            // 增加下载次数
            learningMaterialMapper.incrementDownloadCount(id);

            return Result.success(material.getFilePath());

        } catch (Exception e) {
            log.error("下载资料失败", e);
            return Result.failure(500, "下载失败: " + e.getMessage());
        }
    }

    // ==================== 管理员方法实现 ====================

    @Override
    public Result<Page<LearningMaterialVO>> getAdminMaterials(Integer current, Integer size,
                                                              Integer auditStatus, String collegeName,
                                                              String subjectType, Integer uploaderId,
                                                              String keyword, String orderBy) {
        try {
            // 检查管理员权限
            User currentUser = getCurrentUser();
            if (currentUser == null || currentUser.getUserRole() != 1) {
                return Result.failure(403, "无管理员权限");
            }

            Page<LearningMaterialVO> page = new Page<>(current, size);
            Page<LearningMaterialVO> result = learningMaterialMapper.getAdminMaterials(
                    page, auditStatus, collegeName, subjectType, uploaderId, keyword, orderBy);

            // 设置审核状态文本
            result.getRecords().forEach(this::setAuditStatusText);

            return Result.success(result);

        } catch (Exception e) {
            log.error("管理员查询资料列表失败", e);
            return Result.failure(500, "查询失败: " + e.getMessage());
        }
    }

    @Override
    public Result<Page<LearningMaterialVO>> getPendingAuditMaterials(Integer current, Integer size) {
        try {
            // 检查管理员权限
            User currentUser = getCurrentUser();
            if (currentUser == null || currentUser.getUserRole() != 1) {
                return Result.failure(403, "无管理员权限");
            }

            Page<LearningMaterialVO> page = new Page<>(current, size);
            Page<LearningMaterialVO> result = learningMaterialMapper.getPendingAuditMaterials(page);

            // 设置审核状态文本
            result.getRecords().forEach(this::setAuditStatusText);

            return Result.success(result);

        } catch (Exception e) {
            log.error("管理员查询待审核资料列表失败", e);
            return Result.failure(500, "查询失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional
    public Result<Void> auditMaterial(MaterialAuditDTO auditDTO) {
        try {
            // 检查管理员权限
            User currentUser = getCurrentUser();
            if (currentUser == null || currentUser.getUserRole() != 1) {
                return Result.failure(403, "无管理员权限");
            }

            // 验证审核状态
            if (auditDTO.getAuditStatus() != 1 && auditDTO.getAuditStatus() != 2) {
                return Result.failure(400, "审核状态无效");
            }

            // 获取资料
            LearningMaterial material = learningMaterialMapper.getMaterialById(auditDTO.getMaterialId());
            if (material == null) {
                return Result.failure(404, "资料不存在");
            }

            // 更新审核状态
            material.setAuditStatus(auditDTO.getAuditStatus());
            material.setAuditTime(new Date());
            material.setAuditReason(auditDTO.getAuditReason());
            learningMaterialMapper.updateById(material);

            String statusText = auditDTO.getAuditStatus() == 1 ? "通过" : "拒绝";
            log.info("管理员{}审核资料{}: {} - {}", currentUser.getId(), auditDTO.getMaterialId(), statusText, material.getTitle());

            return Result.success();

        } catch (Exception e) {
            log.error("审核资料失败", e);
            return Result.failure(500, "审核失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional
    public Result<Void> batchAuditMaterials(MaterialBatchAuditDTO batchAuditDTO) {
        try {
            // 检查管理员权限
            User currentUser = getCurrentUser();
            if (currentUser == null || currentUser.getUserRole() != 1) {
                return Result.failure(403, "无管理员权限");
            }

            // 验证审核状态
            if (batchAuditDTO.getAuditStatus() != 1 && batchAuditDTO.getAuditStatus() != 2) {
                return Result.failure(400, "审核状态无效");
            }

            // 批量更新
            Date auditTime = new Date();
            for (Integer materialId : batchAuditDTO.getMaterialIds()) {
                LearningMaterial material = new LearningMaterial();
                material.setId(materialId);
                material.setAuditStatus(batchAuditDTO.getAuditStatus());
                material.setAuditTime(auditTime);
                material.setAuditReason(batchAuditDTO.getAuditReason());
                learningMaterialMapper.updateById(material);
            }

            String statusText = batchAuditDTO.getAuditStatus() == 1 ? "通过" : "拒绝";
            log.info("管理员{}批量审核资料: {} - 数量: {}", currentUser.getId(), statusText, batchAuditDTO.getMaterialIds().size());

            return Result.success();

        } catch (Exception e) {
            log.error("批量审核资料失败", e);
            return Result.failure(500, "批量审核失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional
    public Result<Void> forceDeleteMaterial(Integer id) {
        try {
            // 检查管理员权限
            User currentUser = getCurrentUser();
            if (currentUser == null || currentUser.getUserRole() != 1) {
                return Result.failure(403, "无管理员权限");
            }

            // 物理删除
            int result = learningMaterialMapper.forceDeleteMaterial(id);
            if (result == 0) {
                return Result.failure(404, "资料不存在");
            }

            log.info("管理员{}强制删除资料: {}", currentUser.getId(), id);
            return Result.success();

        } catch (Exception e) {
            log.error("强制删除资料失败", e);
            return Result.failure(500, "删除失败: " + e.getMessage());
        }
    }

    @Override
    public Result<List<StatDTO>> getAuditStatistics() {
        try {
            // 检查管理员权限
            User currentUser = getCurrentUser();
            if (currentUser == null || currentUser.getUserRole() != 1) {
                return Result.failure(403, "无管理员权限");
            }

            List<StatDTO> stats = learningMaterialMapper.getAuditStatusStats();
            return Result.success(stats);

        } catch (Exception e) {
            log.error("获取审核统计失败", e);
            return Result.failure(500, "获取统计失败: " + e.getMessage());
        }
    }

    @Override
    public Result<List<StatDTO>> getDailyUploadStatistics() {
        try {
            // 检查管理员权限
            User currentUser = getCurrentUser();
            if (currentUser == null || currentUser.getUserRole() != 1) {
                return Result.failure(403, "无管理员权限");
            }

            List<StatDTO> stats = learningMaterialMapper.getDailyUploadStats();
            return Result.success(stats);

        } catch (Exception e) {
            log.error("获取每日上传统计失败", e);
            return Result.failure(500, "获取统计失败: " + e.getMessage());
        }
    }

    @Override
    public Result<List<StatDTO>> getTopDownloadStatistics() {
        try {
            // 检查管理员权限
            User currentUser = getCurrentUser();
            if (currentUser == null || currentUser.getUserRole() != 1) {
                return Result.failure(403, "无管理员权限");
            }

            List<StatDTO> stats = learningMaterialMapper.getTopDownloadMaterials();
            return Result.success(stats);

        } catch (Exception e) {
            log.error("获取热门下载统计失败", e);
            return Result.failure(500, "获取统计失败: " + e.getMessage());
        }
    }

    // ==================== 私有方法 ====================

    /**
     * 获取当前用户
     */
    private User getCurrentUser() {
        // 先尝试从UserHolder获取
        User user = UserHolder.getCurrentUser();
        if (user != null) {
            return user;
        }

        // 从request中获取
        Object userObj = request.getAttribute("currentUser");
        if (userObj instanceof User) {
            return (User) userObj;
        }

        return null;
    }

    /**
     * 验证上传文件
     */
    private Result<Void> validateFile(MultipartFile file) {
        if (file == null || file.isEmpty()) {
            return Result.failure(400, "文件不能为空");
        }

        // 检查文件大小
        if (file.getSize() > MAX_FILE_SIZE) {
            return Result.failure(400, "文件大小不能超过50MB");
        }

        // 检查文件类型
        String fileExtension = getFileExtension(file.getOriginalFilename());
        if (!ALLOWED_FILE_TYPES.contains(fileExtension.toLowerCase())) {
            return Result.failure(400, "不支持的文件类型，支持的类型: " + String.join(", ", ALLOWED_FILE_TYPES));
        }

        return Result.success();
    }

    /**
     * 上传文件到OSS
     */
    private String uploadFileToOSS(MultipartFile file) throws Exception {
        // 生成文件名
        String originalFilename = file.getOriginalFilename();
        String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
        String fileName = "learning-materials/" + UUID.randomUUID().toString().replaceAll("-", "") + suffix;

        // 创建PutObjectRequest对象
        PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, fileName, file.getInputStream());

        // 上传文件
        ossClient.putObject(putObjectRequest);

        // 生成文件访问路径
        return "https://" + bucketName + "." + endpoint + "/" + fileName;
    }

    /**
     * 获取文件扩展名
     */
    private String getFileExtension(String filename) {
        if (filename == null || !filename.contains(".")) {
            return "";
        }
        return filename.substring(filename.lastIndexOf(".") + 1);
    }

    /**
     * 构建LearningMaterialVO
     */
    private LearningMaterialVO buildMaterialVO(LearningMaterial material, String uploaderUsername) {
        LearningMaterialVO vo = new LearningMaterialVO();
        BeanUtils.copyProperties(material, vo);
        vo.setUploaderUsername(uploaderUsername);
        setAuditStatusText(vo);
        return vo;
    }

    /**
     * 设置审核状态文本
     */
    private void setAuditStatusText(LearningMaterialVO vo) {
        if (vo.getAuditStatus() == null) {
            vo.setAuditStatusText("未知");
            return;
        }
        
        switch (vo.getAuditStatus()) {
            case 0:
                vo.setAuditStatusText("待审核");
                break;
            case 1:
                vo.setAuditStatusText("审核通过");
                break;
            case 2:
                vo.setAuditStatusText("审核拒绝");
                break;
            default:
                vo.setAuditStatusText("未知");
                break;
        }
    }
}
